package edu.cmu.ece.ds.droidchat.util;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.drawable.Drawable;
import android.util.Log;

import com.facebook.android.Facebook;

import edu.cmu.ece.ds.droidchat.ChatWindowActivity;
import edu.cmu.ece.ds.droidchat.NetworkService;
import edu.cmu.ece.ds.droidchat.message.CreateSessionInfoResponseMessage;
import edu.cmu.ece.ds.droidchat.message.CreateSessionInfoResponseMessageR;
import edu.cmu.ece.ds.droidchat.model.ChatSessionInfo;
import edu.cmu.ece.ds.droidchat.model.StringConstants;
import edu.cmu.ece.ds.droidchat.model.UserInfo;

/**
 * App-wide shared methods come here.
 */
public class Toolbox {
    private final static String TAG = "Toolbox";
    private static Facebook facebook = new Facebook(
            StringConstants.FACEBOOK_APP_ID);

    // key is the username
    private static Hashtable<String, UserInfo> userInfoHashtable = new Hashtable<String, UserInfo>(
            400);

    // key is the chatSessionID
    private static Hashtable<String, ChatSessionInfo> chatSessionHashtable = new Hashtable<String, ChatSessionInfo>();

    // key stores username
    // value stores public modulus
    private static Hashtable<String, BigInteger> userModulusHashtable =
        new Hashtable<String, BigInteger>();

    // key stores username
    // value stores public exponent
    private static Hashtable<String, BigInteger> userExponentHashtable =
        new Hashtable<String, BigInteger>();

    public final static ImageDownloader imageDownloader = new ImageDownloader();
    // private final static Gson gson = new Gson();
    private static UserInfo myInfo;

    private static NetworkService mService;

    private static int dead = 0;
    
    public static Drawable loadFacebookProfilePicture(String fbId) {
        try {
            InputStream is = (InputStream) new URL(
                    StringConstants.URL_PREFIX_FACEBOOK_GRAPH + fbId
                    + StringConstants.URL_POSTFIX_FACEBOOK_PICTURE)
            .getContent();
            Drawable d = Drawable.createFromStream(is, "src name");
            is.close();
            return d;
        } catch (IOException e) {
            Log.e(TAG, "LoadFacebookProfileImage error.");
            return null;
        }
    }

    public static Facebook getFacebookObject() {
        return facebook;
    }

    /**
     * returns all the ChatSessionInfo in chatSessionHashtable
     */
    public static Collection<ChatSessionInfo> getAllChatSessions(){
        return chatSessionHashtable.values();
    }

    /**
     * invitee calls this method to create a new chat session when 
     *   an multi-user chat invitation is received
     *     
     *   chat session id is not generated
     */
    public static String addNewMultiUserChatSessionInfo(String invitorUsername,
			String chatID, HashMap<String, Integer> existingParticipants, 
			int t) {
    	System.out.println("addNewMultiUserChatSessionInfo()" +
        	" INVITEE VERSION");
    	System.out.println("inviter=" + invitorUsername);
    	System.out.println(existingParticipants);
    	
    	Iterator<ChatSessionInfo> itr = chatSessionHashtable.values()
        .iterator();

        boolean chatSessionExists = false;
    	
        ChatSessionInfo chatSession = null;
        while (itr.hasNext()) {
            chatSession = itr.next();
            
            // existing participants + 1 inviter
            if (chatSession.numberOfParticipants() == existingParticipants.keySet().size()+1) {
            	HashMap<String, ChatSessionInfo.ParticipantLife> pList = chatSession.getParticipants();
            	
            	if(pList.keySet().containsAll(existingParticipants.keySet()) 
            			&& pList.keySet().contains(invitorUsername)){
            		
            		System.out.println("contains all exisiting participants and inviter");
            		chatSessionExists = true;
                    break;
            	}
            }
        }
        if (chatSessionExists == false) {
            ChatSessionInfo newInfo = null;
            newInfo = new ChatSessionInfo(chatID, invitorUsername);
            newInfo.setBrandNew(true);
            chatSessionHashtable.put(newInfo.getSessionid(), newInfo);
            newInfo.setT(t);
            return newInfo.getSessionid();
        } else {
            //System.out.println("chatSessionExists=" + chatSessionExists);
            chatSession.setBrandNew(false);
            return chatSession.getSessionid();
        }
	}
    
    /**
     * invitee calls this method to create a new chat session chat session id is
     * not generated
     */
    public static String addNewOneOnOneChatSessionInfoByUsername(
            String invitorUsername, String chatID) {

        System.out.println("addNewOneOnOneChatSessionInfoByUsername()" +
        " INVITEE VERSION");

        Iterator<ChatSessionInfo> itr = chatSessionHashtable.values()
        .iterator();

        boolean chatSessionExists = false;

        //System.out.println(chatSessionHashtable.keySet().size());

        ChatSessionInfo chatSession = null;
        while (itr.hasNext()) {
            chatSession = itr.next();

            //System.out.println(chatSession);
            //System.out.println();

            if (chatSession.numberOfParticipants() == 1) {
                HashMap<String, ChatSessionInfo.ParticipantLife> pList = chatSession.getParticipants();

                Iterator<String> itr2 = pList.keySet().iterator();

                String onlyParticipant = itr2.next();

                if(onlyParticipant.equals(invitorUsername)){
                    // will this ever happen?
                    //  the only participant sends you another invitation??
                    //  possible only if he is explicitly exiting from this chat session
                    chatSessionExists = true;
                    break;
                }
            }

            // indeed there is someone being invited
            /*if (chatSession.getUsername()!=null && chatSession.getUsername().equals(invitorUsername)) {
                if (chatSession.participants.size() == 1) {
                    chatSessionExists = true;
                }
            }*/
        }

        if (chatSessionExists == false) {
            //System.out.println("chatSessionExists=" + chatSessionExists
            //		+ " " + chatID);
            ChatSessionInfo newInfo = null;
            newInfo = new ChatSessionInfo(chatID, invitorUsername);
            newInfo.setBrandNew(true);
            chatSessionHashtable.put(newInfo.getSessionid(), newInfo);
            return newInfo.getSessionid();

            //UserInfo u = retrieveUserInfoByUsername(invitorUsername);
            // newInfo.addParticipant(invitorUsername, u.getUserIP());
        } else {
            //System.out.println("chatSessionExists=" + chatSessionExists);
            chatSession.setBrandNew(false);
            return chatSession.getSessionid();
        }
    }

    /**
     * inviter calls this method to create a new chat session generates a new
     * chat session id
     *
     * must check that if there is already a one-on-one chat session requested to that
     *  invitee and that invitee has not yet responded
     */
    public static String addNewOneOnOneChatSessionInfoByUsername(
            String inviteeUsername) {

        System.out.println("in addNewOneOnOneChatSessionInfoByUsername() invitor version...");

        Iterator<ChatSessionInfo> itr = chatSessionHashtable.values()
        .iterator();

        boolean chatSessionExists = false;

        ChatSessionInfo chatSession = null;

        while (itr.hasNext()) {
            chatSession = itr.next();

            if(chatSession.getUsername()==null){
                System.out.println("WTF1");
            }

            if(inviteeUsername==null){
                System.out.println("WTF2");
            }

            // the chat session has an invited user
            if (chatSession.getUsername()!=null && chatSession.getUsername().equals(inviteeUsername)) {
                /*if (chatSession.participants.size() == 1) {
                    chatSessionExists = true;
                    System.out.println(" chat session exists and invitee has already responded yes ");
                    break;
                } else*/ if(chatSession.numberOfParticipants() == 0){
                    chatSessionExists = true;
                    System.out.println("1-on-1 chat session exists" +
                    " but invitee has not yet responded yes ");
                    break;
                }
            } else if (chatSession.getUsername()==null){
                if (chatSession.numberOfParticipants() == 1) {
                    HashMap<String, ChatSessionInfo.ParticipantLife> pList =
                        chatSession.getParticipants();

                    Iterator<String> itr2 = pList.keySet().iterator();

                    String onlyParticipant = itr2.next();

                    if(onlyParticipant.equals(inviteeUsername)){
                        // will this ever happen?
                        //  the only participant sends you another invitation??
                        //  possible only if he is explicitly exiting from this chat session
                        System.out.println("1-on-1 chat session exists" +
                        " and invitee has already responded yes ");
                        chatSessionExists = true;
                        break;
                    }
                }
            }
        }

        if (chatSessionExists == false) {
            ChatSessionInfo newInfo = null;
            newInfo = new ChatSessionInfo();
            newInfo.setUsername(inviteeUsername);
            newInfo.setBrandNew(true);
            chatSessionHashtable.put(newInfo.getSessionid(), newInfo);
            return newInfo.getSessionid();
        } else {
            chatSession.setBrandNew(false);
            return chatSession.getSessionid();
        }
    }

    /**
     * Calls this method when 
     *  1) the user explcitly says he wants to leave the chat session
     *     - remove = true
     *  2) when the chat session has no one else in it
     *     - remove = false
     */
    public static void removeChatSession(String chatSessionID, boolean remove) {
        /*if(chatSessionHashtable.containsKey(chatSessionID)){
            chatSessionHashtable.remove(chatSessionID);
        }*/
    	
    	if(chatSessionHashtable.containsKey(chatSessionID)){
    		if(remove==true){
    			chatSessionHashtable.remove(chatSessionID);
    		}else{
    			chatSessionHashtable.get(chatSessionID).setDead(true);
    			////
    			String newID = "dead" + getNextDead();
    			chatSessionHashtable.get(chatSessionID).setSessionid(newID);
    			ChatSessionInfo temp = chatSessionHashtable.remove(chatSessionID);
    			chatSessionHashtable.put(newID, temp);
    		}
    	}
    }

    /**
     * Calls this method when the user explcitly says he wants
     *  to log out
     */
    public static void removeAllChatSessions() {
        chatSessionHashtable.clear();
    }

    public static void storeUserKey(CreateSessionInfoResponseMessageR msg) {
        Log.e("store Key information", "user=" + msg.getUsername());

        String user = msg.getUsername();

        BigInteger exp = msg.getPublic_exponent();
        BigInteger mod = msg.getPublic_modulus();

        userModulusHashtable.put(user, mod);
        userExponentHashtable.put(user, exp);
    }

    public static void storeUserKey(CreateSessionInfoResponseMessage msg) {
        Log.e("store Key information", "user=" + msg.getUsername());

        String user = msg.getUsername();

        BigInteger exp = msg.getPublic_exponent();
        BigInteger mod = msg.getPublic_modulus();

        userModulusHashtable.put(user, mod);
        userExponentHashtable.put(user, exp);
    }

    public static BigInteger getUserModulus(String username){
        return userModulusHashtable.get(username);
    }

    public static BigInteger getUserExponent(String username){
        return userExponentHashtable.get(username);
    }

    public static void putCreationKey(CreateSessionInfoResponseMessage msg) {
        String invitee = msg.getUsername();

        System.out.println(" in putCreationKey(), invitee is " + invitee);

        Iterator<ChatSessionInfo> itr = chatSessionHashtable.values()
        .iterator();

        while (itr.hasNext()) {
            ChatSessionInfo chatSession = itr.next();

            if (chatSession == null) {
                System.out.println(" chatSession is null");
            } else {
                System.out.println(" chatSession is not null");
            }

            if (chatSession.getUsername() == null) {
                System.out.println(" chatSession.getUsername() is null");
            } else {
                System.out.println(" chatSession.getUsername() is not null");
            }

            if (chatSession.getUsername().equals(invitee)
                    && chatSession.isPendingForMyInvitation()) {
                chatSession.setPublicExponent(msg.getPublic_exponent());
                chatSession.setPublicModulus(msg.getPublic_modulus());
            }
        }
    }

    public static void addParticipant(String username, String chatSessionID,
            String ip) {

        System.out.println("addParticipant()");
        System.out.println("username=" + username);
        System.out.println("chat session id=" + chatSessionID);
        System.out.println("ip=" + ip);

        if (chatSessionHashtable.containsKey(chatSessionID)) {
            ChatSessionInfo info = chatSessionHashtable.get(chatSessionID);

            // info.participants.add(username);
            System.out.println("adding");
            info.addParticipant(username, ip);
        }

    }


    /**
     * return true if any user has been set to a non-neighbor
     *
     */
    public static boolean checkRoundNumber(int latestRound) {
        //Stack<String> usernameToBeRemoved = new Stack<String>();

        boolean changed = false;

        for (String username : userInfoHashtable.keySet()) {
            UserInfo cur = userInfoHashtable.get(username);
            if (cur.getRound() + 5 < latestRound) {
                // too old...
                Log.d("checkRoundNumber", cur.getUsername() + " is too old");
                //usernameToBeRemoved.push(username);
                cur.setNeighbor(false);
                changed = true;
            }
        }

        return changed;

        /*while (!usernameToBeRemoved.isEmpty()) {
            Log.d("checkRoundNumber", usernameToBeRemoved.peek()
                    + " is removed");
            userInfoHashtable.remove(usernameToBeRemoved.pop());
        }*/
    }

    // returns the current number of neighbors in the hashtable
    public static int numNeighbors() {
        //return userInfoHashtable.keySet().size();

        int n = 0;

        for(UserInfo u: userInfoHashtable.values()){
            if(u.isANeighbor())
                n++;
        }

        return n;
    }

    public static Collection<UserInfo> retrieveAllUsers() {
        return userInfoHashtable.values();
    }

    /**
     * retrieve all neighbors
     */
    public static Collection<UserInfo> retrieveAllNeighbors(){
        ArrayList<UserInfo> neighbors = new ArrayList<UserInfo>();
        neighbors.addAll(userInfoHashtable.values());

        //System.out.println("hashtable key set size:" + userInfoHashtable.keySet().size());

        Iterator<UserInfo> itr = neighbors.iterator();

        while(itr.hasNext()){
            UserInfo u = itr.next();
            if(u.isANeighbor()==false){
                // not a neighbor
                itr.remove();
            }
        }

        return neighbors;
    }

    /**
     * retrieve all neighbors that's not in the participantsList
     */
    public static Collection<UserInfo> retrieveAllNeighborsNotInList(
            ChatSessionInfo chInfo){
        Set<String> participantsList = chInfo.getParticipants().keySet();
        ArrayList<UserInfo> neighbors = new ArrayList<UserInfo>();
        neighbors.addAll(userInfoHashtable.values());

        //System.out.println("hashtable key set size:" + userInfoHashtable.keySet().size());

        Iterator<UserInfo> itr = neighbors.iterator();

        while(itr.hasNext()){
            UserInfo u = itr.next();
            if(u.isANeighbor()==false){
                // not a neighbor
                itr.remove();
            }
        }

        itr = neighbors.iterator();
        while(itr.hasNext()){
            UserInfo u = itr.next();
            if(participantsList.contains(u.getUsername())){
                // already in the participant list
                itr.remove();
            }
        }

        return neighbors;
    }

    // add a new user into the hashtable 'userInfoHashtable'
    public static void addNewUser(UserInfo u) {
        userInfoHashtable.put(u.getUsername(), u);
    }

    public static UserInfo retrieveUserInfoByUsername(String username) {
        UserInfo uInfo = null;

        /*Log.e("Toolbox - retrieveUserInfoByUsername()",
                "username=" + username);*/

        if (userInfoHashtable.containsKey(username)) {
            uInfo = userInfoHashtable.get(username);
        }
        return uInfo;
    }

    public static void removeAllUsers(){
    	Iterator<UserInfo> itr = userInfoHashtable.values().iterator();
    	while(itr.hasNext()){
    		UserInfo u = itr.next();
    		u.setNeighbor(false);
    	}
    }
    
    /*public static UserInfo retrieveUserInfo(String username) {


        if(userInfoHashtable.containsKey(username)){
            return userInfoHashtable.get(username);
        }

        return null;

        //UserInfo uInfo = null;
        /*if ((uInfo = userInfoHashtable.get(username)) == null) {
            Log.e(TAG, "User info for username=" + username
                    + " not found in hashtable.");
            uInfo = new UserInfo("Faulty Username", "FAULTING Nickname");
        }
        return uInfo;*/
    //}

    
    /**
     * returns the number of live chat sessions
     */
    public static int numChatSessions() {
    	Hashtable<String, ChatSessionInfo> clone = 
    		new Hashtable<String, ChatSessionInfo>(chatSessionHashtable);
    	
    	int cnt = 0;
    	
    	for(ChatSessionInfo ch: clone.values()){
    		if(ch.isDead()==false){
    			cnt++;
    		}
    	}
		return cnt;
	}
    
    public static ChatSessionInfo getChatSession(String chatSessionID) {
        ChatSessionInfo attr = null;

        if (chatSessionHashtable == null) {
            System.out.println("chatSessionHashtable is null");
        }

        if (chatSessionID == null) {
            System.out.println("sessionid is null");
        }

        if (chatSessionHashtable.containsKey(chatSessionID)) {
            attr = chatSessionHashtable.get(chatSessionID);
        }
        return attr;
    }

    public static void addNewChatSession(ChatSessionInfo attr) {
        if (chatSessionHashtable.get(attr) == null) {
            // put a new chat session attribute into the table, we have a new
            // session
            // it to userInfoHashtable (putToUserInfoHashtable) before it sends
            // out the broadcast
            Log.e(TAG, "new session with id=" + attr.getSessionid()
                    + " is added");
            chatSessionHashtable.put(attr.getSessionid(), attr);
        }
    }

    // debug only
    public static ArrayList<UserInfo> getUserInfoArray() {
        return new ArrayList<UserInfo>(userInfoHashtable.values());
    }

    /*public static void putToUserInfoHashtablec(UserInfo userInfo) {
        Toolbox.userInfoHashtable.put(userInfo.getUsername(), userInfo);
    }*/

    public static UserInfo getMyInfo() {
        return myInfo;
    }

    public static void setMyInfo(UserInfo myInfo) {
        Toolbox.myInfo = myInfo;
    }

    static enum ParseState {
        NORMAL, ESCAPE, UNICODE_ESCAPE
    }

    /**
     * Converts Unicode to UTF8.
     *
     * @param s
     *            The string in unicode.
     *
     * @see http://www.xinotes.org/notes/note/813/
     */
    public static String convertUnicodeEscape(String s) {
        char[] out = new char[s.length()];

        ParseState state = ParseState.NORMAL;
        int j = 0, k = 0, unicode = 0;
        char c = ' ';
        for (int i = 0; i < s.length(); i++) {
            c = s.charAt(i);
            if (state == ParseState.ESCAPE) {
                if (c == 'u') {
                    state = ParseState.UNICODE_ESCAPE;
                    unicode = 0;
                } else { // we don't care about other escapes
                    out[j++] = '\\';
                    out[j++] = c;
                    state = ParseState.NORMAL;
                }
            } else if (state == ParseState.UNICODE_ESCAPE) {
                if ((c >= '0') && (c <= '9')) {
                    unicode = (unicode << 4) + c - '0';
                } else if ((c >= 'a') && (c <= 'f')) {
                    unicode = (unicode << 4) + 10 + c - 'a';
                } else if ((c >= 'A') && (c <= 'F')) {
                    unicode = (unicode << 4) + 10 + c - 'A';
                } else {
                    throw new IllegalArgumentException(
                    "Malformed unicode escape");
                }
                k++;

                if (k == 4) {
                    out[j++] = (char) unicode;
                    k = 0;
                    state = ParseState.NORMAL;
                }
            } else if (c == '\\') {
                state = ParseState.ESCAPE;
            } else {
                out[j++] = c;
            }
        }

        if (state == ParseState.ESCAPE) {
            out[j++] = c;
        }

        return new String(out, 0, j);
    }

    /**
     * a simple helper method translate IP in the "xxx.xxx.xxx.xxx" format into
     * a 8-byte long
     */
    public static long ipToInt(String addr) {
        //Log.e(TAG, "ipToInt: addr=" + addr);
        String[] addrArray = addr.split("\\.");

        long num = 0;
        for (int i = 0; i < addrArray.length; i++) {
            int power = 3 - i;

            num += ((Integer.parseInt(addrArray[i]) % 256 * Math
                    .pow(256, power)));
        }
        return num;
    }

    public static String intToIp(int i) {
        return ((i >> 24) & 0xFF) + "." + ((i >> 16) & 0xFF) + "."
        + ((i >> 8) & 0xFF) + "." + (i & 0xFF);
    }

    /*
     * start the ChatWindowActivity to chat with the user corresponds to uInfo
     * and the chat session is identified by chInfo
     */
    public static void createChatWindowActivity(Context context,
            boolean isInvitor, String chatSessionId) {
        ChatSessionInfo chInfo;
        chInfo = Toolbox.getChatSession(chatSessionId);
        if (!isInvitor) {
            chInfo.setPendingForMyInvitation(false);
        }
        Intent i = new Intent(context, ChatWindowActivity.class);
        i.putExtra(StringConstants.EXTRA_CHAT_SESSION_ID, chInfo.getSessionid());
        i.putExtra(StringConstants.EXTRA_IS_INVITING, isInvitor);
        context.startActivity(i);
    }

    /**
     * create the ChatWindowActvity because user wants to
     *  return to an existing chat session
     */
    public static void returnToChatWindowActivity(Context context,
            String chatSessionId){
    	Log.e(TAG, "returnToChatWindowActivity()");
    	
        ChatSessionInfo chInfo;
        chInfo = Toolbox.getChatSession(chatSessionId);

        if(chInfo==null){
        	Log.e("returnToChatWindowActivity()", "chInfo is null");
        	return;
        }
        
        Intent i = new Intent(context, ChatWindowActivity.class);
        i.putExtra(StringConstants.EXTRA_CHAT_SESSION_ID, chInfo.getSessionid());
        i.putExtra(StringConstants.EXTRA_IS_RETURNING, true);
        context.startActivity(i);
    }

    public static ArrayList<BigInteger> getCreationKey(String chatSessionID) {

        ArrayList<BigInteger> pubKeys = new ArrayList<BigInteger>();

        if (chatSessionHashtable == null) {
            System.out.println("chatSessionHashtable is null");
        }

        if (chatSessionHashtable.containsKey(chatSessionID)) {
            ChatSessionInfo info = chatSessionHashtable.get(chatSessionID);
            pubKeys.add(info.getPublicExponent()); // exponent
            pubKeys.add(info.getPublicModulus()); // modulus
            return pubKeys;
        }

        return null;
    }

    // record who is using the service
    private static List<String> serviceUserList = Collections
    .synchronizedList(new LinkedList<String>());

    public synchronized static boolean bindService(Activity a, Intent service,
            ServiceConnection conn, int flags, String callerTag) {
        serviceUserList.add(callerTag);
        Log.e(TAG,
                "added callerTag=" + callerTag + ", size="
                + serviceUserList.size());
        return a.bindService(service, conn, flags);
    }

    public synchronized static void unbindService(Activity a,
            ServiceConnection conn, String callerTag) {
        a.unbindService(conn);
        serviceUserList.remove(callerTag);
        Log.e(TAG, "removed callerTag=" + callerTag + ", size="
                + serviceUserList.size());
    }

    public static int getServiceUserListSize() {
        return serviceUserList.size();
    }

    public static String getServiceUserListString() {
        return serviceUserList.toString();
    }

    public static NetworkService getService(){
        return mService;
    }

    public static void setService(NetworkService service){
        mService = service;
    }

    /**
     *  given a Set of Strings that represent the usernames
     *   return a String that separate these usernames by ","
     */
    public static String[] formatExistingParticipants(Set<String> participants) {
        //StringBuffer str = new StringBuffer();

        // make sure the keys are in actual sorted order
        // important bc
        ArrayList<String> toBeSorted = new ArrayList<String>();

        for (String username : participants) {
            toBeSorted.add(username);
        }

        // sort the ArrayList of Strings
        Collections.sort(toBeSorted);

        System.out.println("formatExistingParticipants() " + toBeSorted);

        /*for (String username : toBeSorted) {
            str.append(username);
            str.append(",");
        }

        return str.subSequence(0, str.length() - 1).toString();*/

        String[] arr = new String[toBeSorted.size()];

        for(int i=0; i<toBeSorted.size(); i++){
            arr[i] = toBeSorted.get(i);
        }
        return arr;
        //return (String[]) toBeSorted.toArray();
    }

    public static int[] formatExistingParticipantsIP(HashMap<String, Integer> existingParticipants){
        // make sure the keys are in actual sorted order
        // important bc
        ArrayList<String> toBeSorted = new ArrayList<String>();

        for (String username : existingParticipants.keySet()) {
            toBeSorted.add(username);
        }

        // sort the ArrayList of Strings
        Collections.sort(toBeSorted);

        System.out.println("formatExistingParticipantsIP() " + toBeSorted);

        int[] toReturn = new int[existingParticipants.keySet().size()];

        int i=0;

        for(String username: toBeSorted){
            toReturn[i] = existingParticipants.get(username);
            i++;
        }

        System.out.println("formatExistingParticipantsIP() " + toReturn);

        return toReturn;
    }

    public static String combineName(String[] existingParticipants,
            String username) {
        String[] newArr = new String[existingParticipants.length+1];
        int i=0;
        for(i=0; i<existingParticipants.length; i++){
            newArr[i] = existingParticipants[i];
        }
        newArr[i] = username;

        Arrays.sort(newArr);

        return Arrays.toString(newArr);
    }

    /**
     * returns true if there is a chat session whose
     * participants are exactly {list, username}
     */
    public static boolean chatSessionExists(Set<String> list, String username) {
        int total = list.size()+1;

        for(String chatSessionID: chatSessionHashtable.keySet()){
            ChatSessionInfo chInfo = chatSessionHashtable.get(chatSessionID);

            if(chInfo.numberOfParticipants() == total){
                // possible match
                ArrayList<String> p = new ArrayList<String>(chInfo.getParticipants().keySet());

                if(p.containsAll(list) && p.contains(username)){
                    return true;
                }
            }
        }

        return false;
    }

    // return my ip address as a String
    public static String getLocalIpAddress() {
        String LOG_TAG = "getLocalIpAddress";
        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
                NetworkInterface intf = en.nextElement();

                Log.d(LOG_TAG, intf.getDisplayName());

                for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
                    InetAddress inetAddress = enumIpAddr.nextElement();
                    if (!inetAddress.isLoopbackAddress()) {
                        return inetAddress.getHostAddress().toString();
                    }
                }
            }
        } catch (SocketException ex) {
            Log.e(LOG_TAG, ex.toString());
        }
        return null;
    }

	public static int getNextDead(){
		return --dead;
	}
}
